﻿using nhCore.db;
using nhCore.Modbus;
using nhCore.nhLib.sql;
using System.Data;
using System.Reflection;
using Decoder = nhCore.Modbus.Decoder;

namespace nhCore
{
    /// <summary>
    /// 传感器实时数据临时保存及定时存入数据库
    /// </summary>
    public class RealData
    {
        /// <summary>
        /// 保存间隔秒数
        /// </summary>
        public int SaveInterval { get; set; } = 60;

        /// <summary>
        /// 设备地址对应的实时数据
        /// </summary>
        private Dictionary<byte, Weathers> DicAddrWeathers { get; set; } = [];

        /// <summary>
        /// 返回查找到的气象数据，没有则新建空数据
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public Weathers FindOrAddWeathers(byte address)
        {
            Weathers weathers;
            if (DicAddrWeathers.TryGetValue(address, out Weathers? value))
            {
                weathers = value;
            }
            else
            {
                weathers = new Weathers()
                {
                    Id = address
                };
                DicAddrWeathers.Add(address, weathers);
            }
            return weathers;
        }

        /// <summary>
        /// 直接修改数据
        /// </summary>
        /// <param name="config"></param>
        /// <param name="value"></param>
        public void WriteWeather(ElementConfig config, double? value)
        {
            Weathers ws = FindOrAddWeathers(config.MappingStationId);
            Decoder wd = new WeatherDecoder
            {   //建立解码器为解码新写入数据。
                ElementConfig = config
            };

            if (!ws.Values.ContainsKey(config.StationReg))
            {
                ws.AddValue(
                    config.StationReg,
                    new Weather()
                    {
                        Config = config,
                    });
            }
            ws.Values[config.StationReg].Value = value;
            ws.Values[config.StationReg].StrValue = value.HasValue ? wd.Convert(value ?? 0) : "-";
            if (!ws.Values.ContainsKey(CoreGlobal.Const_TimeIndex))
            {
                ws.Values.Add(CoreGlobal.Const_TimeIndex,
                    new Weather()
                    {
                        Config = new ElementConfig
                        {
                            Name = "时间",
                            StationReg = CoreGlobal.Const_TimeIndex,
                            ElementType = CoreGlobal.Const_time,
                        }
                    });
            }
            CgqTimeDecoder ctd = new();
            Weather wTime = ws.Values[CoreGlobal.Const_TimeIndex];
            wTime.Value = DateTime.Now.Ticks;
            wTime.StrValue = ctd.Convert(wTime.Value ?? 0);
        }

        /// <summary>
        /// 读出实时数据
        /// </summary>
        /// <param name="address">设备地址</param>
        /// <returns>气象数据</returns>
        public Weathers ReadWeathers(byte address)
        {
            return DicAddrWeathers.TryGetValue(address, out Weathers? value)
                ? value
                : new();
        }

        /// <summary>
        /// 声明一个私有的构造方法，让外部无法调用这个类的构造方法 
        /// </summary>
        /// <param name="database"></param>
        /// <param name="saveInterval"></param>
        private RealData(int saveInterval = 10)
        {
            //Database = Access.Singleton;
            SaveInterval = saveInterval;

            System.Timers.Timer timer = new System.Timers.Timer(1000);
            timer.Elapsed += OnTimerSave;
            timer.AutoReset = true;
            timer.Enabled = true;
        }

        /// <summary>
        /// 每秒运行一次，超时数据请空，到时保存历史数据
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnTimerSave(object? source, System.Timers.ElapsedEventArgs e)
        {
            DateTime now = e.SignalTime;

            foreach (var ws in DicAddrWeathers.Values.ToList())
            {
                if (now - ws.UpdateTime > CoreGlobal.OutTime)//超时清空数据
                {
                    foreach (var w in ws.Values.Values)
                    {
                        w.Value = null;
                        w.StrValue = "-";
                    }
                }
            }
            if ((now.Minute * 60 + now.Second) % SaveInterval == 0)
            {
                DateTime dateTime = new(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); //时间为整秒
                using EnvDbContext db = new();
                foreach (var ws in DicAddrWeathers.Values.ToList())
                {
                    List<string> columns = [];
                    List<string> values = [];

                    foreach (var w in ws.Values.Values)
                    {
                        if (w.Config.StationReg == CoreGlobal.Const_TimeIndex)
                        {
                            columns.Add(nameof(Data.Time));
                            values.Add(dateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                            columns.Add(nameof(Data.Id));
                            values.Add(ws.Values.Values.First().Config.MappingStationId.ToString()); //保存到映射Id
                        }
                        else
                        {
                            columns.Add(w.Config.GetDataFieldName());
                            values.Add(w.Value?.ToString() ?? "NULL");
                        }
                    }
                    SQLite.InsertData(db, nameof(EnvDbContext.Datas), columns, values);
                }
            }
        }

        #region 单例模式  
        private static readonly RealData _nhRealData = new();

        static RealData() { }

        /// <summary>
        /// 返回对象单例
        /// </summary>
        public static RealData Singleton
        {
            get { return _nhRealData; }
        }
        #endregion
    }
}
